﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Bovril.PlayingCards.French;

namespace Bovril.Poker.HoldEmBuddy
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        public MainWindowViewModel()
        {
            String myDocumentsDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            String holdEmDataPathname = System.IO.Path.Combine(myDocumentsDirectory, "HoldEm.dat");
            holdEmAnalyser_ = HoldEmAnalyser.Load(holdEmDataPathname);

            ranks_ = RankValue.GetAllValuesAsStrings();
            suits_ = SuitValue.GetAllValuesAsStrings();

            Card1Rank = ranks_[0];
            Card1Suit = suits_[0];
            Card2Rank = ranks_[0];
            Card2Suit = suits_[1];
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public IEnumerable<String> Ranks
        {
            get
            {
                return ranks_;
            }
        }

        public IEnumerable<String> Suits
        {
            get
            {
                return suits_;
            }
        }

        public String Card1Rank
        {
            get { return card1Rank_; }
            set
            {
                if (card1Rank_ != value)
                {
                    card1Rank_ = value;
                    OnHoleChanged();
                }
            }
        }

        public String Card1Suit
        {
            get { return card1Suit_; }
            set
            {
                if (card1Suit_ != value)
                {
                    card1Suit_ = value;
                    OnHoleChanged();
                }
            }
        }

        public String Card2Rank
        {
            get { return card2Rank_; }
            set
            {
                if (card2Rank_ != value)
                {
                    card2Rank_ = value;
                    OnHoleChanged();
                }
            }
        }

        public String Card2Suit
        {
            get { return card2Suit_; }
            set
            {
                if (card2Suit_ != value)
                {
                    card2Suit_ = value;
                    OnHoleChanged();
                }
            }
        }

        public String Card3Rank
        {
            get { return card3Rank_; }
            set
            {
                if (card3Rank_ != value)
                {
                    card3Rank_ = value;
                }
            }
        }

        public String Card3Suit
        {
            get { return card3Suit_; }
            set
            {
                if (card3Suit_ != value)
                {
                    card3Suit_ = value;
                }
            }
        }

        public bool Card3Active { get; private set; }

        public String Card4Rank
        {
            get { return card4Rank_; }
            set
            {
                if (card4Rank_ != value)
                {
                    card4Rank_ = value;
                }
            }
        }

        public String Card4Suit
        {
            get { return card4Suit_; }
            set
            {
                if (card4Suit_ != value)
                {
                    card4Suit_ = value;
                }
            }
        }

        public bool Card4Active { get; private set; }

        public String Card5Rank
        {
            get { return card5Rank_; }
            set
            {
                if (card5Rank_ != value)
                {
                    card5Rank_ = value;
                }
            }
        }

        public String Card5Suit
        {
            get { return card5Suit_; }
            set
            {
                if (card5Suit_ != value)
                {
                    card5Suit_ = value;
                }
            }
        }

        public bool Card5Active { get; private set; }

        public String Card6Rank
        {
            get { return card6Rank_; }
            set
            {
                if (card6Rank_ != value)
                {
                    card6Rank_ = value;
                }
            }
        }

        public String Card6Suit
        {
            get { return card6Suit_; }
            set
            {
                if (card6Suit_ != value)
                {
                    card6Suit_ = value;
                }
            }
        }

        public bool Card6Active { get; private set; }

        public String Card7Rank
        {
            get { return card7Rank_; }
            set
            {
                if (card7Rank_ != value)
                {
                    card7Rank_ = value;
                }
            }
        }

        public String Card7Suit
        {
            get { return card7Suit_; }
            set
            {
                if (card7Suit_ != value)
                {
                    card7Suit_ = value;
                }
            }
        }

        public bool Card7Active { get; private set; }

        public String HolePercentile
        {
            get
            {
                if (holeArchetype_ != null)
                {
                    return String.Format("{0}", holeArchetype_.WinPercentile.ToString("0.000"));
                }

                return String.Empty;
            }
        }

        public String HoleOrder
        {
            get
            {
                if (holeArchetype_ != null)
                {
                    return String.Format("{0} of {1}", holeArchetype_.OrderIndex + 1, holdEmAnalyser_.NumHoleArchetypes);
                }

                return String.Empty;
            }
        }

        public String WinPercentile
        {
            get
            {
                if (holeArchetype_ != null)
                {
                    return String.Format("{0}", winPercentile_.ToString("0.000"));
                }

                return String.Empty;
            }
        }

        private void OnHoleChanged()
        {
            if (card1Rank_ == null || card1Suit_ == null || card2Rank_ == null || card2Suit_ == null)
                return;

            hole_ = new Hole(
                new Card(RankValue.FromString(card1Rank_), SuitValue.FromString(card1Suit_)),
                new Card(RankValue.FromString(card2Rank_), SuitValue.FromString(card2Suit_)));
            holeArchetype_ = holdEmAnalyser_.GetHoleArchetype(hole_);
            NotifyPropertyChanged("HolePercentile");
            NotifyPropertyChanged("HoleOrder");
        }

        public void CalculateWinPercentile()
        {
            bool holeOK = (card1Rank_ != null && card1Suit_ != null && card2Rank_ != null && card2Suit_ != null);
            bool flopOK = (card3Rank_ != null && card3Suit_ != null && Card3Active && 
                           card4Rank_ != null && card4Suit_ != null && Card4Active &&
                           card5Rank_ != null && card5Suit_ != null && Card5Active);
            bool turnOK = (flopOK && card6Rank_ != null && card6Suit_ != null && Card6Active);
            bool riverOK = (turnOK && card7Rank_ != null && card7Suit_ != null && Card7Active);

            if (!holeOK || !flopOK)
            {
                winPercentile_ = 0;
            }
            else if (!turnOK)
            {
                winPercentile_ = holdEmAnalyser_.GetHoleFlopPercentile(
                    hole_,
                    new Flop(
                        new Card(RankValue.FromString(card3Rank_), SuitValue.FromString(card3Suit_)),
                        new Card(RankValue.FromString(card4Rank_), SuitValue.FromString(card4Suit_)),
                        new Card(RankValue.FromString(card5Rank_), SuitValue.FromString(card5Suit_))));
            }
            else if (!riverOK)
            {
                winPercentile_ = holdEmAnalyser_.GetHoleTurnPercentile(
                    hole_,
                    new Turn(
                        new Card(RankValue.FromString(card3Rank_), SuitValue.FromString(card3Suit_)),
                        new Card(RankValue.FromString(card4Rank_), SuitValue.FromString(card4Suit_)),
                        new Card(RankValue.FromString(card5Rank_), SuitValue.FromString(card5Suit_)),
                        new Card(RankValue.FromString(card6Rank_), SuitValue.FromString(card6Suit_))));
            }
            else
            {
                winPercentile_ = holdEmAnalyser_.GetHoleRiverPercentile(
                    hole_,
                    new River(
                        new Card(RankValue.FromString(card3Rank_), SuitValue.FromString(card3Suit_)),
                        new Card(RankValue.FromString(card4Rank_), SuitValue.FromString(card4Suit_)),
                        new Card(RankValue.FromString(card5Rank_), SuitValue.FromString(card5Suit_)),
                        new Card(RankValue.FromString(card6Rank_), SuitValue.FromString(card6Suit_)),
                        new Card(RankValue.FromString(card7Rank_), SuitValue.FromString(card7Suit_))));
            }

            NotifyPropertyChanged("WinPercentile");
        }

        public void Save()
        {
            String myDocumentsDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            String holdEmDataPathname = System.IO.Path.Combine(myDocumentsDirectory, "HoldEm.dat");
            holdEmAnalyser_.Save(holdEmDataPathname);
        }

        // This method is called by the Set accessor of each property. 
        // The CallerMemberName attribute that is applied to the optional propertyName 
        // parameter causes the property name of the caller to be substituted as an argument. 
        private void NotifyPropertyChanged(String propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        private String[] ranks_;
        private String[] suits_;

        private String card1Rank_;
        private String card1Suit_;
        private String card2Rank_;
        private String card2Suit_;
        private String card3Rank_;
        private String card3Suit_;
        private String card4Rank_;
        private String card4Suit_;
        private String card5Rank_;
        private String card5Suit_;
        private String card6Rank_;
        private String card6Suit_;
        private String card7Rank_;
        private String card7Suit_;

        private HoldEmAnalyser holdEmAnalyser_;

        private Hole hole_;
        private HoleArchetype holeArchetype_;
        private double winPercentile_;
    }
}
